package com.totoro.tyrank.manager;

import com.totoro.tyrank.TyRank;
import com.totoro.tyrank.constants.PlayerIdentityConst;
import com.totoro.tyrank.constants.StaticSystemVarConst;
import com.totoro.tyrank.data.PlayerData;
import com.totoro.tyrank.mapper.RankPlayerDataMapper;
import com.totoro.tyrank.mapper.impl.RankPlayerDataMapperImpl;
import com.totoro.tyrank.handle.PaginatorHandler;
import com.totoro.tyrank.utils.ColorUtil;
import com.totoro.tyrank.utils.DateUtil;
import com.totoro.tyrank.utils.ListUtil;
import lombok.Getter;
import lombok.SneakyThrows;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;

import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 玩家数据管理器
 */
public class PlayerDataManager {

    private final Plugin plugin;

    private static final String PLAYER_DATA_PATH = TyRank.getInstance().getDataFolder().getPath() + StaticSystemVarConst.FILE_SEPARATOR + StaticSystemVarConst.PLAYER_DATA_CONFIG_DEFAULT_NAME;
    private static final File PLAYER_DATA_FILE = new File(PLAYER_DATA_PATH);

    /**
     * 所有排行榜对应玩家数据Map
     */
    @Getter
    private final Map<String, LinkedList<PlayerData>> playersDataMap;

    /**
     * 所有排行榜对应的分页器
     */
    @Getter
    private final Map<String, PaginatorHandler<PlayerData>> rankPaginatorMap = new ConcurrentHashMap<>();

    /**
     * 操作数据库的Mapper
     */
    private final RankPlayerDataMapper rankPlayerDataMapper = new RankPlayerDataMapperImpl();

    public PlayerDataManager(Plugin plugin) {
        playersDataMap = new HashMap<>();
        this.plugin = plugin;
    }

    /**
     * 获取所有排行榜当前数据
     */
    public void loadRankPlayerData() {
        playersDataMap.clear();
        Set<String> rankIdSet = TyRank.getRankingManager().getRankDataMap().keySet();
        for (String rankId : rankIdSet) {
            loadRankPlayerData(rankId);
        }
    }

    public boolean updatePlayerData(PlayerData playerData) {
        // 获取对应的元素索引
        if(! playersDataMap.containsKey(playerData.getRankId())) {
            return false;
        }
        LinkedList<PlayerData> playerDataList = playersDataMap.get(playerData.getRankId());
        int index = IntStream.range(0, playerDataList.size())
                .filter(i -> playerDataList.get(i).getPlayerIdentity().equals(playerData.getPlayerIdentity())).findFirst().orElse(-1);
        if(index == -1) {
            return false;
        }
        playerDataList.set(index, playerData);
        saveRankPlayerData(playerData.getRankId(), Stream.of(playerData).collect(Collectors.toList()));
        return true;
    }

    /**
     * 获取单个排行榜的所有数据
     * @param rankId 排行榜ID
     */
    public void loadRankPlayerData(String rankId) {
        LinkedList<PlayerData> playerDataList;
        if(TyRank.getConfigManager().getConfigData().getMySQLData().getEnable()) {
            playerDataList = ListUtil.sortByRankingAsc(rankPlayerDataMapper.selectAllPlayerDataByRankId(rankId));
        } else {
            YamlConfiguration rankDataConfig = getRankConfigurationSection(rankId);
            if(null == rankDataConfig) {
                TyRank.getInstance().getServer().getConsoleSender()
                        .sendMessage(StaticSystemVarConst.CONSOLE_PREFIX +
                                String.format(ColorUtil.color("&c排行榜: &e[%s] &c数据获取失败，请检查该排行榜数据文件..."), rankId));
                return;
            }
            Set<String> playerIdentitySet = rankDataConfig.getKeys(false);
            playerDataList = new LinkedList<>();
            for (String playerIdentity : playerIdentitySet) {
                ConfigurationSection playerDataSection = rankDataConfig.getConfigurationSection(playerIdentity);
                int ranking = playerDataSection.getInt("ranking");
                String currentValue = playerDataSection.getString("current-value");
                Boolean rewardReceive = playerDataSection.getBoolean("reward-receive");
                String updateDateTime = playerDataSection.getString("update-date-time");
                playerDataList.add(new PlayerData(playerIdentity, rankId, ranking, currentValue, rewardReceive, updateDateTime, false));
            }
            playerDataList = ListUtil.sortByRankingAsc(playerDataList);
        }
        playersDataMap.put(rankId, playerDataList);
        rankPaginatorMap.put(rankId, new PaginatorHandler<>(playerDataList, 28));
        List<String> playerIdentityList = playerDataList.stream().map(PlayerData::getPlayerIdentity).collect(Collectors.toList());
        // 缓存头颅
        TyRank.getSkullCacheHandler().batchCacheSkulls(playerIdentityList)
                .thenRun(() -> plugin.getServer().getConsoleSender().sendMessage(StaticSystemVarConst.CONSOLE_PREFIX +
                        ColorUtil.color(String.format("&c排行榜 &e[%s] &c的头颅数据缓存完毕，本次共缓存了 &e%s &c个玩家的头颅数据", rankId, playerIdentityList.size()))));
    }

    /**
     * 获取玩家对象根据排行榜ID和名次
     * @param rankId
     * @param ranking
     * @return
     */
    public PlayerData getPlayerDataByRankIdAndRanking(String rankId, Integer ranking) {
        if (! playersDataMap.containsKey(rankId)) {
            return null;
        }
        LinkedList<PlayerData> playerDataList = playersDataMap.get(rankId);
        if(ListUtil.isBlank(playerDataList)) {
            return null;
        }
        List<PlayerData> playerDataListResult = playerDataList.stream().filter(playerData -> playerData.getRanking().equals(ranking)).collect(Collectors.toList());
        if(ListUtil.isBlank(playerDataListResult)) {
            return null;
        }
        return playerDataListResult.get(0);
    }

    /**
     * 获取玩家名根据玩家标识
     * @param playerIdentity 玩家标识
     * @return
     */
    public String getPlayerName(String playerIdentity) {
        if(TyRank.getConfigManager().getConfigData().getPlayerIdentity().equals(PlayerIdentityConst.PLAYER_UUID)) {
            Player player = Bukkit.getPlayer(UUID.fromString(playerIdentity));
            if(null != player && player.isOnline()) {
                return player.getName();
            } else {
                OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(UUID.fromString(playerIdentity));
                if(null != offlinePlayer) {
                    return offlinePlayer.getName();
                }
                return playerIdentity;
            }
        } else {
            return playerIdentity;
        }
    }


    /**
     * 获取玩家排行榜数据对象根据玩家对象和排行榜ID
     * @param rankId
     * @return
     */
    public PlayerData getPlayerDataByRankId(Player player, String rankId) {
        if (! playersDataMap.containsKey(rankId)) {
            return null;
        }
        LinkedList<PlayerData> playerDataList = playersDataMap.get(rankId);
        String playerIdentity = getPlayerIdentityByPlayer(player);
        Optional<PlayerData> optionalPlayerData = playerDataList.stream().filter(playerData -> playerData.getPlayerIdentity().equals(playerIdentity)).findFirst();
        return optionalPlayerData.orElse(null);
    }

    /**
     * 根据玩家对象获取玩家标识
     * @param player
     * @return
     */
    public String getPlayerIdentityByPlayer(Player player) {
        if(TyRank.getConfigManager().getConfigData().getPlayerIdentity().equals(PlayerIdentityConst.PLAYER_UUID)) {
            return player.getUniqueId().toString();
        }
        return player.getName();
    }

    /**
     * 根据玩家标识获取玩家对象
     * @param playerIdentity
     * @return
     */
    public OfflinePlayer getPlayer(String playerIdentity) {
        if(TyRank.getConfigManager().getConfigData().getPlayerIdentity().equals(PlayerIdentityConst.PLAYER_UUID)) {
            Player player = Bukkit.getPlayer(UUID.fromString(playerIdentity));
            if(null != player && player.isOnline()) {
                return player;
            } else {
                return Bukkit.getOfflinePlayer(UUID.fromString(playerIdentity));
            }
        } else {
            Player player = Bukkit.getPlayer(playerIdentity);
            if(null != player && player.isOnline()) {
                return player;
            } else {
                return Bukkit.getOfflinePlayer(playerIdentity);
            }
        }
    }

    /**
     * 存储排行数据
     * @param rankId
     * @param playerDataList
     */
    @SneakyThrows
    public void saveRankPlayerData(String rankId, List<PlayerData> playerDataList) {
        // 数据库存储数据
        if(TyRank.getConfigManager().getConfigData().getMySQLData().getEnable()) {
            for (PlayerData playerData : playerDataList) {
                // 如果已经存在则修改
                if(rankPlayerDataMapper.selectIsHavePlayerByRankId(playerData.getPlayerIdentity(), rankId)) {
                    // 是否清除
                    if(playerData.getIsClear()) {
                        // 删除
                        rankPlayerDataMapper.removeRankPlayerData(playerData);
                    } else {
                        // 修改
                        rankPlayerDataMapper.updateRankPlayerData(playerData);
                    }
                } else {
                    // 新增
                    rankPlayerDataMapper.insertRankPlayerData(playerData);
                }
            }
        } else {
            YamlConfiguration rankDataConfig = getRankConfigurationSection(rankId);
            File rankPlayerDataFile = new File(PLAYER_DATA_PATH + StaticSystemVarConst.FILE_SEPARATOR + rankId + ".yml");
            // 循环所有玩家进行设置
            for (PlayerData playerData : playerDataList) {
                YamlConfiguration playerDataConfig = new YamlConfiguration();
                // 判断是否清除
                if(playerData.getIsClear()) {
                    rankDataConfig.set(playerData.getPlayerIdentity(), null);
                } else {
                    playerDataConfig.set("ranking", playerData.getRanking());
                    playerDataConfig.set("current-value", playerData.getCurrentValue());
                    playerDataConfig.set("reward-receive", playerData.getRewardReceive().toString());
                    playerDataConfig.set("update-date-time", DateUtil.currentDateStr());
                    rankDataConfig.set(playerData.getPlayerIdentity(), playerDataConfig);
                }
            }
            // 设置完成，进行保存
            rankDataConfig.save(rankPlayerDataFile);
        }
    }

    /**
     * 获取某个排行的所有玩家
     * @param rankId
     * @return
     */
    public Set<OfflinePlayer> getAllRankPlayer(String rankId) {
        // 如果是数据库
        Set<String> playerIdentitySet;
        if(TyRank.getConfigManager().getConfigData().getMySQLData().getEnable()) {
            playerIdentitySet = new HashSet<>(rankPlayerDataMapper.selectAllPlayerIdentityByRankId(rankId));
        } else {
            YamlConfiguration rankDataConfig = getRankConfigurationSection(rankId);
            playerIdentitySet = rankDataConfig.getKeys(false);
        }
        // 判断玩家标识方式
        Set<OfflinePlayer> playerSet = new HashSet<>(playerIdentitySet.size());
        if (TyRank.getConfigManager().getConfigData().getPlayerIdentity().equals(PlayerIdentityConst.PLAYER_UUID)) {
            for (String playerIdentity : playerIdentitySet) {
                Player player = Bukkit.getPlayer(UUID.fromString(playerIdentity));
                if(null == player || !player.isOnline()) {
                    playerSet.add(Bukkit.getOfflinePlayer(UUID.fromString(playerIdentity)));
                } else {
                    playerSet.add(Bukkit.getPlayer(UUID.fromString(playerIdentity)));
                }
            }
        } else {
            for (String playerIdentity : playerIdentitySet) {
                Player player = Bukkit.getPlayer(UUID.fromString(playerIdentity));
                if(null == player || !player.isOnline()) {
                    playerSet.add(Bukkit.getOfflinePlayer(playerIdentity));
                } else {
                    playerSet.add(Bukkit.getPlayer(playerIdentity));
                }
            }
        }
        return playerSet;
    }

    @SneakyThrows
    public YamlConfiguration getRankConfigurationSection(String rankId) {
        createPlayerFile();
        // 判断该rankId文件是否已经创建，没有则创建
        File rankPlayerDataFile = new File(PLAYER_DATA_PATH + StaticSystemVarConst.FILE_SEPARATOR + rankId + ".yml");
        if(!rankPlayerDataFile.exists()) {
            rankPlayerDataFile.createNewFile();
        }
        // 获取该排行玩家数据文件的config
        return YamlConfiguration.loadConfiguration(rankPlayerDataFile);

    }

    /**
     * 生成默认文件
     */
    public void createPlayerFile() {
        // 如果排行文件不存在则创建
        if(! PLAYER_DATA_FILE.exists()) {
            PLAYER_DATA_FILE.mkdirs();
        }
    }

}
